//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Text;
using System.Xml.Linq;
using System.Xml.Serialization;
using LargoCommon.Abstract;
namespace LargoCommon.Music
{
/// Bit Range.
///
/// BitRange represents interval of bits inside of binary structure.
[Serializable]
[XmlRoot]
public sealed class BitRange : ICloneable, IComparable {
#region Constructors
/// Initializes a new instance of the BitRange class. Serializable.
public BitRange()
{
}
/// Initializes a new instance of the BitRange class.
/// Order of system.
/// Starting bit.
/// Length of the range.
public BitRange(byte order, byte givenBitFrom, byte length) {
//// Contract.Requires(order > 0);
//// This all code is bit slow and very often used - any guess how to improve it?
if (order == 0) {
throw new ArgumentException("Order of bit range must not be 0.");
}
this.Order = order;
this.BitFrom = givenBitFrom;
if (length > 0) {
int bitTo;
checked {
bitTo = this.BitFrom + length - 1;
if (bitTo < 0) {
bitTo = 0;
}
if (bitTo > order - 1) {
bitTo = order - 1;
}
}
this.BitTo = (byte)bitTo;
//// this.BitTo = (byte)Math.Max(this.BitFrom + length - 1, 0);
//// this.BitTo = (byte)Math.Min(this.BitTo, this.Order - 1);
this.Length = (byte)(this.BitTo - this.BitFrom + 1);
}
else {
this.BitTo = 0;
this.Length = 0;
}
}
#endregion
#region Properties - Xml
/// Gets Xml representation.
/// Property description.
public XElement GetXElement {
get {
//// Contract.Requires(this.BitRange != null);
var xmlBitRange = new XElement(
"B",
new XAttribute("Order", this.Order),
new XAttribute("Start", this.BitFrom),
new XAttribute("Length", this.Length));
return xmlBitRange;
}
}
#endregion
#region Properties
/// Gets or sets order of system.
/// Property description.
public byte Order { get; set; }
/// Gets or sets the first bit of the range.
/// Property description.
public byte BitFrom { get; set; }
/// Gets or sets length of the range.
/// Property description.
public byte Length { get; set; }
/// Gets a value indicating whether IsEmpty.
/// Property description.
public bool IsEmpty => this.Length <= 0;
/// Gets or sets the last bit of the range.
/// Property description.
[XmlIgnore]
public byte BitTo { get; set; }
#endregion
#region Static operators
//// TICS rule 7@526: Reference types should not override the equality operator (==)
//// public static bool operator ==(BitRange range1, BitRange range2) { return object.Equals(range1, range2); }
//// public static bool operator !=(BitRange range1, BitRange range2) { return !object.Equals(range1, range2); }
//// but TICS rule 7@530: Class implements interface 'IComparable' but does not implement '==' and '!='.
///
/// Implements the operator <.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator <(BitRange object1, BitRange object2) {
if (object1 != null && object2 != null) {
return object1.BitFrom < object2.BitFrom;
}
return false;
}
///
/// Implements the operator >.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator >(BitRange object1, BitRange object2) {
if (object1 != null && object2 != null) {
return object1.BitFrom > object2.BitFrom;
}
return false;
}
///
/// Implements the operator <=.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator <=(BitRange object1, BitRange object2) {
if (object1 != null && object2 != null) {
return object1.BitFrom <= object2.BitFrom;
}
return false;
}
///
/// Implements the operator >=.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator >=(BitRange object1, BitRange object2) {
if (object1 != null && object2 != null) {
return object1.BitFrom >= object2.BitFrom;
}
return false;
}
#endregion
#region Public methods
/// Makes a deep copy of the BitRange object.
/// Returns object.
public object Clone() {
return new BitRange(this.Order, this.BitFrom, this.Length);
}
#endregion
#region Serialization
///
/// Sets Xml representation.
///
/// Xml Element.
public void SetXElement(XElement element) {
Contract.Requires(element != null);
//// if (element == null) { return; }
this.Order = XmlSupport.ReadByteAttribute(element.Attribute("Order"));
this.BitFrom = XmlSupport.ReadByteAttribute(element.Attribute("Start"));
this.Length = XmlSupport.ReadByteAttribute(element.Attribute("Length"));
}
#endregion
#region Comparison
/// Support for potential comparing of bit ranges.
/// Object to be compared.
/// Returns value.
public int CompareTo(object obj) {
return obj is BitRange br ? this.BitFrom.CompareTo(br.BitFrom) : 0;
//// This kills the DataGrid
//// throw new ArgumentException("Object is not a BitRange");
}
/// Test of equality.
/// Object to be compared.
/// Returns value.
public override bool Equals(object obj) {
//// check null (this pointer is never null in C# methods)
if (object.ReferenceEquals(obj, null)) {
return false;
}
if (object.ReferenceEquals(this, obj)) {
return true;
}
if (this.GetType() != obj.GetType()) {
return false;
}
return this.CompareTo(obj) == 0;
}
/// Support of comparison.
/// Returns value.
public override int GetHashCode() {
return this.BitFrom.GetHashCode();
}
#endregion
#region Operations
/// Returns intersection with the given Range.
/// Given range.
/// Resulting range.
public bool Intersect(BitRange range) {
if (range == null) {
return false;
}
var b1 = Math.Max(range.BitFrom, this.BitFrom);
var b2 = Math.Min(range.BitTo, this.BitTo);
return b1 <= b2;
}
/// Returns intersection with the given Range.
/// Given range.
/// Resulting range.
public BitRange IntersectionWith(BitRange range) {
if (range == null) {
return null;
}
var b1 = Math.Max(range.BitFrom, this.BitFrom);
var b2 = Math.Min(range.BitTo, this.BitTo);
var br = b1 <= b2 ? new BitRange(this.Order, b1, (byte)(b2 - b1 + 1)) : new BitRange(this.Order, 0, 0);
return br;
}
///
/// Bit to stops at.
///
/// The bit stop.
/// Returns value.
public BitRange StopAt(byte bitStop) {
var b1 = this.BitFrom;
var b2 = Math.Min(bitStop, this.BitTo);
var br = b1 <= b2 ? new BitRange(this.Order, b1, (byte)(b2 - b1 + 1)) : new BitRange(this.Order, 0, 0);
return br;
}
/// Gets a value indicating whether the range contains the given bit.
/// Given bit.
/// Logical value.
public bool ContainsBit(byte givenBit) {
return (this.BitFrom <= givenBit) && (givenBit <= this.BitTo);
}
/// Checks if the Range Contains the given range.
/// Given range.
/// Logical value.
public bool CoverRange(BitRange range) {
if (range == null) {
return false;
}
return (this.BitFrom <= range.BitFrom) && (range.BitTo <= this.BitTo);
}
#endregion
#region String representation
/// String representation of the object.
/// Returns value.
public override string ToString() {
var s = new StringBuilder();
s.Append(this.BitFrom.ToString("D", CultureInfo.CurrentCulture.NumberFormat));
s.Append("-");
s.Append(this.BitTo.ToString("D", CultureInfo.CurrentCulture.NumberFormat));
s.Append("(");
s.Append(this.Length.ToString("D", CultureInfo.CurrentCulture.NumberFormat));
s.Append(")");
return s.ToString();
}
#endregion
}
}